Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.

...powered by www.netzwerkartist.de...

 << zurück
Visual C# 2005 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2005

Visual C# 2005
1.320 S., mit 2 CDs, 59,90 Euro
Galileo Computing
ISBN 3-89842-586-X
gp Kapitel 26 Datenbankzugriff mit ADO.NET
  gp 26.1 Eine kleine Einführung
  gp 26.2 Die Verbindung zu einer Datenquelle herstellen
    gp 26.2.1 Der Inhalt der Verbindungszeichenfolge
    gp 26.2.2 Die Authentifizierung
    gp 26.2.3 Das Öffnen einer Verbindung
    gp 26.2.4 Schließen einer Verbindung
    gp 26.2.5 Die Dauer des Verbindungsaufbaus
    gp 26.2.6 Eigenschaften eines »Connection«-Objekts
    gp 26.2.7 Die Ereignisse eines »Connection«-Objekts
    gp 26.2.8 Unterstützung bei Projekten mit grafischer Benutzeroberfläche
  gp 26.3 Das »Command«-Objekt
    gp 26.3.1 Erzeugen eines »Command«-Objekts
    gp 26.3.2 Ausführen des »Command«-Objekts
    gp 26.3.3 Aktionsabfragen mit »ExecuteNonQuery« absetzen
    gp 26.3.4 Auswahlabfragen mit »ExecuteReader«
    gp 26.3.5 Abfragen, die genau ein Ergebnis liefern
    gp 26.3.6 Parametrisierte Abfragen
    gp 26.3.7 Die Unterstützung des Visual Studios 2005
  gp 26.4 Der »DataAdapter« als Bindeglied zwischen Datenbank und verbindungslosen Objekten
    gp 26.4.1 Die Konstruktoren der Klasse »DataAdapter«
    gp 26.4.2 Den lokalen Datenspeicher mit der Methode »Fill« füllen
    gp 26.4.3 Abrufen von Schemainformationen
    gp 26.4.4 Die Unterstützung des Visual Studios 2005
  gp 26.5 Das »DataSet«-Objekt
    gp 26.5.1 Ein »DataSet«-Objekt erzeugen
    gp 26.5.2 Das »DataSet« füllen
    gp 26.5.3 Tabellen- und Spaltenbezeichner zuordnen
  gp 26.6 »DataTable«-Objekte
    gp 26.6.1 Die Zeilen und Spalten in einer »DataTable«
    gp 26.6.2 Mit mehreren Tabellen arbeiten
    gp 26.6.3 Änderungen an einer »DataTable« vornehmen
    gp 26.6.4 Datenausgabe in WinForms mit dem Visual Studio 2005
  gp 26.7 Aktualisieren der Datenbank
    gp 26.7.1 Aktualisieren mit dem »CommandBuilder«-Objekt
    gp 26.7.2 Manuell gesteuerte Aktualisierungen
    gp 26.7.3 Aktualisieren mit »ExecuteNonQuery«
    gp 26.7.4 Manuelles Aktualisieren mit dem DataAdapter
    gp 26.7.5 Den zu aktualisierenden Datensatz in der Datenbank suchen
    gp 26.7.6 Den Benutzer über die fehlgeschlagenen Aktualisierungen informieren
    gp 26.7.7 Die konfliktverursachenden Datenzeilen bei der Datenbank abfragen


Galileo Computing

26.5 Das »DataSet«-Objekt  downtop

Wäre man gezwungen, eine Rangfolge der ADO.NET-Typen nach ihrer Wichtigkeit aufzustellen, würde DataSet zweifelsfrei an erster Position stehen. Diese Klasse bildet den Kern von ADO.NET, um den herum sich fast alles andere rankt.

Ein DataSet ist in erster Linie ein Container – ein Container für eine oder auch mehrere Tabellen, die sich im lokalen Datenspeicher befinden. Um welche Tabellen einer Datenbank es sich handelt und welche Datenzeilen in den Tabellen enthalten sind, wird durch das Command-Objekt beschrieben, dessen Referenz die Eigenschaft SelectCommand des DataAdapters enthält. Zwischen den Tabellen in einem DataSet können Beziehungen eingerichtet werden, genauso wie im Original. Damit ist ein DataSet ein temporäres Abbild der Originaldatenbank – zumindest ein Ausschnitt davon.

Der verbindungsorientierte DataReader mag zwar in manchen Situationen den Anforderungen genügen, aber er ist nicht sehr flexibel. Zwischen den Datenzeilen kann nicht beliebig navigiert werden, Datenzeilen können nicht verändert werden – ganz zu schweigen von einer Suche nach bestimmten Datensätzen, einer Sortierung oder Filterung. Mit anderen Worten: Sollen Daten nicht nur angezeigt, sondern in irgendeiner Art und Weise bearbeitet werden, führt praktisch kein Weg am DataSet vorbei.


Galileo Computing

26.5.1 Ein »DataSet«-Objekt erzeugen  downtop

Die Klasse DataSet befindet sich, wie viele andere Klassen, die nicht providerspezifisch sind, im Namespace System.Data. In den meisten Fällen ist der parameterlose Konstruktor vollkommen ausreichend, um ein DataSet-Objekt zu erhalten.


DataSet ds = new DataSet();

Soll das DataSet einen Namen erhalten, bietet sich alternativ der einparametrisierte Konstruktor an:


DataSet ds = new DataSet("DSAutoren");

Der Name kann auch über die Eigenschaft DataSetName festgelegt oder abgerufen werden.


Galileo Computing

26.5.2 Das »DataSet« füllen  downtop

Zum Leben erweckt wird ein DataSet-Objekt nicht durch die Instanziierung der Klasse, sondern vielmehr durch den Aufruf der Fill-Methode des DataAdapters.


...
string strSQL = "SELECT * FROM authors";
SqlDataAdapter da = new SqlDataAdapter(strSQL, con);
DataSet ds = new DataSet();
da.Fill(ds);
...

Das Ergebnis der Abfrage enthält alle Datensätze der Tabelle authors. Diese Datensätze sind in einer Tabelle enthalten, die durch ein DataTable-Objekt beschrieben wird.


Galileo Computing

26.5.3 Tabellen- und Spaltenbezeichner zuordnen  toptop

Um ein DataSet gleichzeitig mit mehreren Tabellen zu füllen, können wir eine Batch-Abfrage absetzen, z.B.:


string strSQL = "SELECT * FROM authors;" +
                "SELECT * FROM titleauthor;" +
                "SELECT * FROM titles";
SqlDataAdapter da = new SqlDataAdapter(strSQL, con);
DataSet ds = new DataSet();
da.Fill(ds);


Hinweis   Der SQL Server unterstützt Batch-Abfragen, jedoch nicht unbedingt jede andere Datenbank. Gegebenenfalls müssen Sie sich in der Dokumentation eines Datenbankmanagementsystems die entsprechende Information besorgen.

Das DataSet beherbergt nun drei Tabellen im lokalen Speicher. In jeder Tabelle sind alle Datensätze der entsprechenden Originaltabelle authors, titles und titleauthor enthalten. Wir könnten nun jeder lokalen Tabelle Datensätze hinzufügen, Datensätze löschen oder ändern. Alle Änderungen werden bei einer erneuten Verbindungsaufnahme unter Aufruf der Update-Methode des DataAdapters in die Originaldatenbank zurückgeschrieben.

Allerdings stehen wir zuvor vor einer Frage: Wie kann ich eine bestimmte Tabelle im DataSet ansprechen, wenn darin mehrere Tabellen enthalten sind? Denn um einen Datensatz zu bearbeiten, muss zuvor festgelegt werden, in welcher Tabelle der entsprechende Datensatz zu finden ist.

Ein DataSet verwaltet alle in ihm enthaltenen Tabellen in einer Auflistung vom Typ DataTableCollection. Die Referenz auf diese Auflistung liefert die Eigenschaft Tables des DataSet-Objekts.


public DataTableCollection Tables {get;}

Der Zugriff auf eine Tabelle im DataSet erfolgt über den Indexer der Auflistung, dem entweder der Verwaltungsindex der Tabelle oder der Bezeichner der Tabelle übergeben werden kann, z.B.:

ds.Tables[0]

Jetzt sollte man auch noch wissen, dass ein DataTable-Objekt seinen Tabellennamen über die Eigenschaft TableName preisgibt. Mit diesen Kenntnissen können wir jetzt die Namen der Tabellen im DataSet abfragen:


foreach(DataTable table in ds.Tables)
  Console.WriteLine(table.TableName);

Die Ausgabe wird nicht – wie vielleicht zu vermuten wäre – authors, titleauthor und titles lauten, sondern:


Table
Table1
Table2

Die Zuordnung von Table zu authors, Table1 zu titleauthor und Table2 zu titles ist in den meisten Fällen nicht wünschenswert. Der DataAdapter bietet daher einen Mechanismus, um den Tabellen im Abfrageergebnis einen anderen Namen zuzuordnen: die Eigenschaft TableMappings, welche die Referenz auf ein DataTableMappingCollection-Objekt liefert.


public DataTableMappingCollection TableMappings {get;}

In der Auflistung DataTableMappingCollection werden Objekte vom Typ DataTableMapping verwaltet. Jedes dieser Objekte ordnet einer Tabelle im DataSet einen Tabellennamen zu.

Am einfachsten ist es, mit der Add-Methode die Auflistung zu füllen.


public DataTableMapping Add(string, string);

Dazu wird dem ersten Parameter die Zeichenfolge übergeben, unter der die Tabelle per Vorgabe in das DataSet gefüllt wird, dem zweiten Parameter teilt man den gewünschten Tabellennamen mit, unter dem die Tabelle im Code angesprochen wird.

Das folgende Codefragment zeigt, wie Sie die DataTableMappingCollection des DataAdapter-Objekts füllen können. Dabei wird davon ausgegangen, dass die oben angeführte Batch-Abfrage abgesetzt wird. Die Zuordnung muss vor dem Füllen des DataSets mit Fill erfolgen, ansonsten bleibt sie wirkungslos.


da.TableMappings.Add("Table", "Autoren");
da.TableMappings.Add("Table1", "TitelAutor");
da.TableMappings.Add("Table2", "Titel");
DataSet ds = new DataSet();
da.Fill(ds);
...

Add ruft implizit den DataTableMapping-Konstruktor auf. Sie können das natürlich auch selbst in die Hand nehmen, müssen dann aber jeder Tabelle über die Eigenschaft SourceTable sagen, welchen Standardnamen sie im DataSet hat, und über DataSetTable, welcher Bezeichner der Tabelle neu zugeordnet werden soll. Das folgende Beispiel zeigt, wie der Code dazu aussieht.


DataTableMapping dtm1 = new DataTableMapping();
dtm1.SourceTable = "Table";
dtm1.DataSetTable = "Autoren";
da.TableMappings.Add((object)dtm1);
DataTableMapping dtm2 = new DataTableMapping();
dtm2.SourceTable = "Table1";
dtm2.DataSetTable = "TitelAutor";
da.TableMappings.Add((object)dtm2);
DataTableMapping dtm3 = new DataTableMapping();
dtm3.SourceTable = "Table2";
dtm3.DataSetTable = "Titel";
da.TableMappings.Add((object)dtm3);
DataSet ds = new DataSet();
da.Fill(ds);
... 

Die Klasse DataTableMapping gehört zum Namespace System.Data.Common. Deutlich ist zu sehen, dass diese Art der Zuordnung mehr Programmieraufwand bedeutet. Daher steht vermutlich außer Frage, welcher Variante Sie den Vorzug geben.

Spaltenzuordnungen in einem »DataSet«

Jeder Spalte der SELECT-Abfrage wird eine Spalte in der DataTable zugeordnet. Als Spaltenbezeichner verwendet ADO.NET dabei den Spaltennamen der Originaltabelle in der Datenbank. Fragen Sie die Datenquelle mit


SELECT au_lname, au_fname, city FROM authors

ab, lauten die Spalten in der DataTable ebenfalls au_lname, au_fname und city. Wünschen Sie andere Spaltenbezeichner, können Sie im SELECT-Statement für die einzelnen Spalten einen Alias angeben, z.B.:


SELECT au_lname AS Zuname, au_fname AS Vorname, city AS Stadt FROM authors

Nun würden in der DataTable die Spaltenbezeichner Zuname, Vorname und Stadt lauten.

Sie können alternativ auch einen anderen Mechanismus einsetzen. Ein DataTableMapping-Objekt hat eine eigene Auflistung, mit der den obligatorischen Spaltenbezeichnern neue zugeordnet werden können. Diese Auflistung ist vom Typ DataColumnMappingCollection und enthält DataColumnMapping-Objekte. Jedes DataColumnMapping-Objekt beschreibt für sich eine Neuzuordnung eines Spaltenbezeichners in einer DataTable. Die vielleicht ein wenig komplex anmutenden Zusammenhänge zwischen DataAdapter, DataTableMapping und DataColumnMapping sind in Abbildung 26.8 anschaulich dargestellt.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 26.8   Die Hierarchie der Zuordnungsklassen

Die Referenz auf die DataColumnMappingCollection stellt die Eigenschaft ColumnMappings der Klasse DataTableMapping bereit:


public DataColumnMappingCollection ColumnMappings {get;}

Um eine Neuzuordnung festzulegen, bietet sich auch hier der Weg über die Add-Methode des DataColumnMappingCollection-Objekts an.


public DataColumnMapping Add(string, string);

Analog zur Add-Methode der DataTableMappingCollection wird dem ersten Parameter der ursprüngliche Spaltenbezeichner, dem zweiten Parameter der gewünschte übergeben.

Das folgende Codefragment zeigt den kompletten Code, der notwendig ist, um neben dem Tabellennamen auch die Spaltenbezeichner einer Abfrage neu festzulegen. Zum Schluss werden die Spaltenneuzuordnungen zur Bestätigung an der Konsole ausgegeben. Der Code im Schleifenkopf zur Ausgabe der Spaltenbezeichner dürfte zwar auch ohne weitere Erläuterungen verständlich sein. Wir werden aber dennoch an anderer Stelle darauf zurückkommen.


string strCon = "...";
SqlConnection con = new SqlConnection(strCon);
string strSQL = "SELECT au_lname, au_fname, city FROM authors";
SqlDataAdapter da = new SqlDataAdapter(strSQL, con);
// Neuzuordnung des Tabellennamens
DataTableMapping dtm = da.TableMappings.Add("Table", "Autoren");
// Neuzuordnung der Spaltenbezeichner
dtm.ColumnMappings.Add("au_lname", "Zuname");
dtm.ColumnMappings.Add("au_fname", "Vorname");
dtm.ColumnMappings.Add("city", "Stadt");
DataSet ds = new DataSet();
da.Fill(ds);
// Konsolenausgabe der Spaltenbezeichner
foreach(DataColumn column in ds.Tables[0].Columns)
   Console.WriteLine(column.ColumnName);

Spaltenzuordnungen einer »DataTable«

Übergeben Sie der Fill-Methode anstelle eines DataSet- ein DataTable-Objekt, müssen Sie ein wenig anders vorgehen, um die Spalten mit eigenen Bezeichnern im lokalen Datenspeicher anzusprechen. Dazu erzeugen Sie auch wieder ein DataTableMapping-Objekt, dem Sie die gewünschten Spaltenbezeichner zuordnen. Bei der Instanziierung von DataTable rufen Sie allerdings den parametrisierten Konstruktor auf, dem der im DataTableMappping zugeordnete Tabellenname übergeben wird.


...
DataTableMapping dtm = da.TableMappings.Add("Table", "Autoren");
// Neuzuordnung der Spaltenbezeichner
dtm.ColumnMappings.Add("au_lname", "Zuname");
dtm.ColumnMappings.Add("au_fname", "Vorname");
dtm.ColumnMappings.Add("city", "Stadt");
DataTable tbl = new DataTable("Autoren");
da.Fill(tbl);
...

Die Eigenschaft »MissingMappingAction« des DataAdapters

Die Neuzuordnung der Tabellen- und Spaltenbezeichner ist eine Option, die vor dem Aufruf der Methode Fill wahrgenommen werden kann oder nicht. Der DataAdapter prüft vor dem Füllen des DataSets, ob die Zuordnungsauflistungen gefüllt sind. Dabei interessiert er sich besonders für die Spaltenzuordnungen.

Für jede Spalte des Abfrageergebnisses überprüft der DataAdapter zuerst, ob dafür eine Zuordnung in der DataColumnMappingCollection angegeben ist. Existiert eine solche nicht, überprüft er im nächsten Schritt seine MissingMappingAction-Eigenschaft. Hier findet er die Antwort darauf, wie er mit einer fehlenden Spaltenangabe umzugehen hat.

Standardmäßig werden Spalten, die nicht im DataColumnMapping-Objekt angegeben sind, mit dem Namen, den sie in der Originaltabelle haben, in die entsprechende DataTable eingetragen. Der DataAdapter kann aber auch angewiesen werden, alle Spalten, die nicht in der Zuordnungstabelle enthalten sind, zu ignorieren. Eine dritte Möglichkeit ist, eine Ausnahme auszulösen, wenn keine Zuordnung angegeben ist.

Die Eigenschaft MissingMappingAction teilt dem DataAdapter mit, wie er zu verfahren hat. Diese Eigenschaft ist vom Typ der gleichnamigen Enumeration MissingMappingAction.


public virtual MissingMappingAction MissingMappingAction {get; set;}

Die drei Member der Enumeration lauten Error, Ignore und Passthrough. Letztere ist die Standardeinstellung.


Tabelle 26.4   Mitglieder der Enumeration »MissingMappingAction«

Member Beschreibung
Error Fehlt eine Spaltenzuordnung, wird eine Ausnahme ausgelöst.
Ignore Fehlt eine Spaltenzuordnung, wird die Spalte in der DataTable ignoriert.
Passthrough Fehlt eine Spaltenzuordnung, wird die Spalte unter ihrem ursprünglichen Namen der DataTable hinzugefügt.

 << zurück
  
  Zum Katalog
Zum Katalog: Visual C# 2005
Visual C# 2005
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Fortgeschrittene Programmierung mit Visual C# 2005






 Fortgeschrittene
 Programmierung
 mit Visual C# 2005


Zum Katalog: Einstieg in Visual C# 2005






 Einstieg in
 Visual C# 2005


Zum Katalog: Einstieg in Visual Basic 2005






 Einstieg in
 Visual Basic 2005


Zum Katalog: Visual Basic 2005






 Visual Basic 2005


Zum Katalog: Java ist auch eine Insel






 Java ist auch eine
 Insel


Zum Katalog: Konzepte und Lösungen für Microsoft-Netzwerke






 Konzepte und
 Lösungen für
 Microsoft-Netzwerke


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo








Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de